#pragma once
#include <unordered_map>
#include <sstream>
#include "Socket.hpp"
#include "ClientInfo.hpp"
#include "threadPool.hpp"

// UDP服务器：
//      1. 面向数据报的
//      2. 无连接的
//      3. 不提供可靠性的
//      即在创建UDP服务器时，只需要创建套接字，并绑定IP与端口号即可


class ChatUdpServer
{
public:
    ChatUdpServer(std::string type = "TCP",uint16_t port = 8888)
        : _port(port)
        ,_sock(type)
    {
        tp = ThreadPool<Client>::GetInstance(std::bind(&ChatUdpServer::Send,this,std::placeholders::_1),3);
        ReuseAddr();
    }
    // 初始化服务器
    void InitServer()
    {
        _sock.Socket();
        _sock.Bind(_port);
        cout << "服务器初始化成功..." << endl;
    }
    // 启动服务器
    // client_msg 是消息
    void Send(Client& client_msg)
    {
        // 给每个客户端发送消息
        
        for(auto& [cli,num] : _clients)
        {
            if(client_msg == cli)
                continue;
            struct sockaddr_in addr;
            addr.sin_family = AF_INET;
            addr.sin_addr.s_addr = inet_addr(cli._ip.c_str());
            addr.sin_port = htons(cli._port);

            int n = sendto(_sock.Fd(),client_msg._msg.c_str(),client_msg._msg.size(),0,(struct sockaddr*)&addr,sizeof(addr));
            if(n == -1)
            {
                cout << "sendto失败" << endl;
                printf("%d - %s", errno, strerror(errno));
                exit(2);
            }
        }
        cout << "给每个客户端发送消息成功" << endl;

    }
    void StartServer()
    {
        cout << "服务器开始运行..." << endl;
        while (true)
        {
            // ssize_t recvfrom(int socket, void *restrict buffer, size_t length,int flags, struct sockaddr *restrict address,socklen_t *restrict address_len);
            char buf[1024];
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int n = recvfrom(_sock.Fd(), buf, sizeof(buf), 0, (struct sockaddr *)(&client), &len);
            if(n > 0)
            {
                std::string client_ip = inet_ntoa(client.sin_addr);
                uint16_t client_port = ntohs(client.sin_port);
                std::stringstream ss;
                ss << client_ip << ":" << std::to_string(client_port) << "# "  << buf;
                std::string msg = ss.str();
                cout << "-----------------" << endl;
                cout << msg << endl;
                cout << "-----------------" << endl;

                // 构建任务放到线程池中
                // 放入消费者缓冲区中
                Client cli(client_ip,client_port,msg);
                _clients[cli];
                tp->PushTask(cli);
                // _clients.insert(make_pair(std::make_pair(client_ip,client_port),msg));

            }
        }
    }
    // 端口复用
    void ReuseAddr()
    {
        int optval = 1;
        setsockopt(_sock.Fd(),SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval));
    }
private:
    Sock _sock;
    uint16_t _port;
    ThreadPool<Client>* tp;
    // 为什么不可以用pair作为key值？ 因为 pair不能进行一个哈希转换
    // 用哈希存储自定义类型，需要提供自定义类型的 哈希计算方法 
    std::unordered_map<Client,int,Client> _clients;
};